package com.org.khtn.command.select;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.google.common.collect.Multimap;
import com.org.khtn.command.QueryPattern;
import com.org.khtn.data.Data;
import com.org.khtn.data.DataTables;
import com.org.khtn.ultilities.Ultilities;

public class Where extends Command {
	final String className = "Where:";

	public Where() {
		resultData = new HashMap<String, Multimap<String, String>>();
		data = new HashMap<String, Map<String, Map<String, String>>>();

	}

	public Object getValueFromPara(String para, String value) {
		final String methodName = "getValueFromPara():";
		String[] temp = para.split("\\.");
		int length = temp.length;
		String type = "";

		if (length == 2) {
			if (!tableExist(temp[0]))
				return null;
			System.out.println(className + methodName + "temp[0]: " + temp[0]);
			System.out.println(className + methodName + "temp[1]: " + temp[1]);
			System.out.println(className + methodName + "tableDefine: "
					+ tableDefine);

			System.out.println(className + methodName
					+ "tableDefine.get(temp[0]): " + tableDefine.get(temp[0]));

			type = tableDefine.get(temp[0]).get(temp[1]);
		}
		if (length == 1) {
			if (ambiguousField(para))
				return null;
			// System.out.println(className + methodName + "12");

			int lengthTemp = currentTable.size();
			for (int i = 0; i < lengthTemp; i++) {
				String tableName = currentTable.get(i);
				System.out.println(className + methodName
						+ "tableDefine.get(tableName):  "
						+ tableDefine.get(tableName));
				DataTables dt = new DataTables(new Data(databaseName, "sdas",
						"myTest\\data\\"));
				type = dt.getTableFieldDefines(tableName, para);
				if (type != null)
					break;
			}
		}
		if (type == null)
			return null;
		switch (type) {
		case "string":
			return value;
		case "int":
			return Integer.parseInt(value);
		}

		// System.out.println(className + methodName + "type: " + type);
		return null;
	}

	public String getValue(String para, String key) {
		final String methodName = "getValue():";
		System.out.println(className + methodName + "vao 1 " );
		
		String[] temp = para.split("\\.");
		int length = temp.length;
		System.out.println(className + methodName + "temp.length:"+temp.length );
		
		String type = "";
		if (length == 2) {
			if (!tableExist(temp[0]))
				return null;
			System.out.println(className + methodName + "temp[0]: " + temp[0]);
			System.out.println(className + methodName + "temp[1]: " + temp[1]);
			int pos = 0;
			// System.out.println(className + methodName + "currentTable: " +
			// currentTable);

			for (; pos < currentTable.size(); pos++) {
				System.out.println(className + methodName + "temp[0]: "
						+ temp[0]);
				System.out.println(className + methodName
						+ "currentTable.get(pos): " + currentTable.get(pos));
				System.out.println(className + methodName + "pos 1: " + pos);

				if (currentTable.get(pos).equalsIgnoreCase(temp[0])) {

					System.out
							.println(className + methodName + "pos 2: " + pos);

					break;
				}
			}
			System.out.println(className + methodName + "pos: " + pos);
			DataTables dt = new DataTables(new Data(databaseName, "Sdasd",
					"mytest\\data\\"));
			String fieldName1="";
		
			int i=0;
		
			String fieldName = dt.getFieldName(dt.getTableName(temp[0]), temp[1]);
			List<String> a = (List<String>) resultData.get(key).get(
					fieldName);
			// System.out.println(className + methodName + "a: " + a);

			return a.get(pos);
		}
		if (length == 1) {
			System.out.println(className + methodName + "vao 2 " );
			
			if (ambiguousField(para))
				return null;
			System.out.println(className + methodName + "vao 2 1" );
			
			DataTables dt = new DataTables(new Data(databaseName, "Sdasd",
					"mytest\\data\\"));
			String fieldName1="";
		
			int i=0;
			for (;i<currentTable.size();i++)
			{
				if(dt.fieldExist(para, currentTable.get(i)))
				{
					fieldName1 = dt.getFieldName(currentTable.get(i), para);
					break;
				}
			}
			System.out.println(className + methodName + "resultData: "
					+ resultData);
			System.out.println(className + methodName + "fieldName1: "
					+ fieldName1);
			System.out.println(className + methodName + "resultData.get(fieldName1): "
					+ resultData.get(fieldName1));
			
			List<String> a = (List<String>) resultData.get(key).get(
					fieldName1);
			return a.get(0);

		}
		return null;

	}
	
	public Vector parse(String condition) {
		String pt = "(>=|<=|=|<|>)";
		String[] a = condition.split(pt);
		int length = a.length;

		Vector<String> result = new Vector<String>();
		for (int i = 0; i < 2; i++) {
			Boolean flag = true;
			try {
				Integer.parseInt(a[i]);

			} catch (NumberFormatException nf) {
				int length1 = a[i].length();
				flag = false;
				if (a[i].charAt(0) == 39 && a[i].charAt(length1 - 1) == 39) {
					String tam = a[i].substring(1, length1 - 1);
					result.add(tam + ":string");
				} else
					result.add(a[i] + ":field");
			}
			if (flag)
				result.add(a[i] + ":int");
		}
		Pattern p = Pattern.compile(pt);
		Matcher m = p.matcher(condition);
		while (m.find()) {
			System.out.println("Found a " + m.group() + ".");
			result.add(m.group());
		}
		return result;
	}

	public static void main(String[] args) {
		Where a = new Where();
		a.where("exists (select * from hocsinh)");
	}

	public boolean oneFieldHaveValue(Map<String, Multimap<String, String>> dd) {
		for (Map.Entry<String, Multimap<String, String>> d : dd.entrySet()) {
			Multimap<String, String> da = d.getValue();
			if (da.isEmpty())
				return false;
			if (da.size() > 1)
				return false;
		}
		return true;
	}

	public Vector<String> getValues(Map<String, Multimap<String, String>> hh) {
		Vector<String> result = new Vector<>();
		for (Map.Entry<String, Multimap<String, String>> dd : hh.entrySet()) {
			Map<String, Collection<String>> tam = dd.getValue().asMap();
			for (Map.Entry<String, Collection<String>> daq : tam.entrySet()) {
				result.addAll(daq.getValue());

			}
		}
		return result;
	}

	public Map<String, Multimap<String, String>> querySelect(String myQuery) {

		int idx = myQuery.indexOf('(');
		final String methodName = "querySelect():";
		System.out.println(className + methodName + "vao 0");
		String pattern1 = "((exists\\s+)|(" + QueryPattern.OBJECT
				+ "\\s+(?i)in\\s+))";
		String pattern2 = QueryPattern.SELECT_PATTERN;

		Pattern p = Pattern.compile(pattern2);
		Matcher m = p.matcher(myQuery);
		SelectQuery sq;
		Map<String, Multimap<String, String>> re = new HashMap<String, Multimap<String, String>>();
		if (m.find()) {
			System.out.println(m.group());
			sq = new SelectQuery(m.group(), databaseName);
			re = sq.executeReader();
			System.out.println(className + methodName + re);
		}
		p = Pattern.compile(pattern1);
		m = p.matcher(myQuery);
		{
			if (m.find()) {
				String[] temp123 = m.group().split("\\s+");
				Ultilities.print_r(temp123);
				Map<String, Multimap<String, String>> result = new HashMap<String, Multimap<String, String>>();
				if (temp123.length == 2) {
					if (!oneFieldHaveValue(re))
						return null; // loi NHIU FIELD
					Vector<String> tam12 = getValues(re);
					System.out.println(className + methodName + "tam12: "
							+ tam12);

					for (Map.Entry<String, Multimap<String, String>> da : resultData
							.entrySet()) {
						String[] aaa = temp123[0].split("\\.");
						System.out.println(className + methodName
								+ "aaa.length: " + aaa.length);
						String value = "";
						if (aaa.length == 1) {
							if (ambiguousField(temp123[0]))
								return null;
							System.out.println(da.getValue());
							List bbb = (List) da.getValue().get(temp123[0]);
							value = (String) bbb.get(0);
						}
						if (aaa.length == 2) {
							if (!tableExist(aaa[0]))
								return null;
							int pos = 0;
							for (; pos < currentTable.size(); pos++) {
								String nam = currentTable.get(pos);
								if (aaa[0].equalsIgnoreCase(nam)) {
									break;
								}
							}
							value = da.getValue().get(temp123[0]).toString();

						}
						System.out.println(className + methodName + "value: "
								+ value);

						for (String t : tam12) {
							System.out.println(className + methodName + "t: "
									+ t);
							System.out.println(className + methodName
									+ "value: " + value);

							if (t.equals(value))
								result.put(da.getKey(), da.getValue());
						}
						System.out.println(className + methodName + "result:"
								+ result);
					}
				}
				System.out.println(className + methodName + "result:" + result);
				return result;

			}
		}
		return null;

	}

	public GroupBy where(String Conditions) {
		final String methodName = "where():";
		System.out.println(className + methodName + "1");
		System.out.println(className + methodName + "Conditions:" + Conditions);
		GroupBy groupBy = new GroupBy();
		groupBy.putData(resultData);
		groupBy.setTables(tables);
		groupBy.setData(data);
		groupBy.putAllCurrentTable(currentTable);
		groupBy.setTableDefine(tableDefine);
		groupBy.databaseName  =databaseName;
		System.out.println(className + methodName + " tableDefine:"
				+ tableDefine);

		if (Conditions == null) {

			System.out.println(className + methodName + "null:" + Conditions);

			return groupBy;
		}
		System.out.println(className + methodName + "Conditions 11: "
				+ Conditions);

		while ((Conditions.charAt(0) == '(' && Conditions.charAt(Conditions
				.length() - 1) == ')')) {
			Conditions = Conditions.substring(1, Conditions.length() - 1);
		}
		String pattern = "\\s*(((?)exists)|(" + QueryPattern.OBJECT
				+ "\\s+(?)in))\\s+\\(\\s*" + QueryPattern.SELECT_PATTERN
				+ "\\s*\\)\\s*";

		if (Conditions.matches(pattern)) {
			System.out.println("mylove");
			resultData = querySelect(Conditions);
			groupBy.putData(resultData);
			groupBy.setTables(tables);
			groupBy.setData(data);
			groupBy.putAllCurrentTable(currentTable);
			groupBy.setTableDefine(tableDefine);
			groupBy.databaseName  =databaseName;
			return groupBy;

		}
		System.out.println(className + methodName + "2");

		String[] operation = Conditions.split(" (and|or) ");
		int length = operation.length;
		Map<Integer, Vector> tam = new HashMap<Integer, Vector>();
		for (int i = 0; i < length; i++) {
			// int idx = Conditions.indexOf(operation[i]);
			// idx += operation[i].length();
			// int idxEnd = Conditions.indexOf(operation[i], idx+1);
			// String temp1 = Conditions.substring(idx,idxEnd);
			// if (temp1.contains("or"))
			// {
			// tam.
			// }
			System.out.println(className + methodName + ":"
					+ parse(operation[i]));
			tam.put(i, parse(operation[i]));
		}
		System.out.println(className + methodName + "3");

		Pattern p = Pattern.compile("(or|and)");
		Matcher m = p.matcher(Conditions);
		while (m.find()) {
			System.out.println("my Found a " + m.group() + ".");
		}
		System.out.println(className + methodName + "4");

		Map<String, Multimap<String, String>> result = new HashMap<String, Multimap<String, String>>();
		// System.out.println(className + methodName + ":" + tam);
		for (Map.Entry<String, Multimap<String, String>> d : resultData
				.entrySet()) {
			boolean[] flag = new boolean[length];

			for (int i = 0; i < length; i++) {
				Vector<String> ob = tam.get(i);
				System.out.println(className + methodName + "ob 1:" + ob);

				if (ob == null) {
					resultData = Ultilities.createError("error 1");
					groupBy.putData(resultData);
					return groupBy;
				}
				Object[] re = new Object[2];

				for (int j = 0; j < 2; j++) {
					String value0 = ob.get(j);

					String[] vat = value0.split(":");
					switch (vat[1]) {
					case "int":
						re[j] = Integer.parseInt(vat[0]);
						break;
					case "string":
						re[j] = vat[0];
						break;
					case "field":
						System.out.println(className + methodName
								+ " tableDefine:" + tableDefine);

						String t = getValue(vat[0], d.getKey());
						re[j] = getValueFromPara(vat[0], t);
						System.out.println(className + methodName + "t:" + t);
						System.out.println(className + methodName + "vat[0]:"
								+ vat[0]);

						if (re[j] == null) {
							resultData = Ultilities.createError("error 2");
							groupBy.putData(resultData);
							return groupBy;
						}
						break;
					}

				}
				String oper = ob.get(2);
				Condition condi = new Condition(re[0], re[1], oper);
				flag[i] = condi.eval();

			}
			boolean ff = true;

			if (flag.length == 1)
				ff = flag[0];
			else {
				m = p.matcher(Conditions);
				ff = flag[0];
				for (int i = 1; i < length; i++) {
					System.out.println(className + methodName + "flag[i]:"
							+ flag[i]);

					String aa = null;
					if (m.find())
						aa = m.group();
					System.out.println(className + methodName + "aa:" + aa);

					switch (aa) {
					case "and":
						if (!flag[i] || !ff)
							ff = false;
						else
							ff = true;
						break;
					case "or":
						if (!flag[i] && !ff)
							ff = false;
						else
							ff = true;
						break;
					}

				}
			}
			if (ff) {
				result.put(d.getKey(), d.getValue());
				System.out.println(className + methodName + "d:" + d);
			}
		}
		System.out.println(className + methodName + "result:" + result);
		groupBy.putData(result);
		groupBy.setTables(tables);
		groupBy.setData(data);
		groupBy.putAllCurrentTable(currentTable);
		groupBy.setTableDefine(tableDefine);
		groupBy.databaseName  =databaseName;
		return groupBy;
	}
}
